package Main;

import java.util.ArrayList;
import java.util.Iterator;

import util.Lib;
import device.Host;
import device.RouteConnect;
import device.Router;
import device.SubNet;

public class Discover {

	/**
	 * get the start router, by looking up the default gateway router
	 * 
	 * @param dottedNetAddress
	 *            net address (IP address) of start host , or "localhost"
	 *            instead
	 */
	public void getStartRouter(String dottedNetAddress) {
		String startIP = lib.getDefaultGateway(dottedNetAddress);
		Router start = new Router(startIP);
		start.routerName = lib.getName(startIP);
		routerList.add(start);
	}

	/**
	 * start topology discovering process via the router given
	 */
	public void start() throws Exception {
		
		// network discovery
		while (!routerList.isEmpty()) {
			Router currentRouter = routerList.remove(0);
			ArrayList<ArrayList<Object>> ipRouteTable = lib.displayTable(lib
					.getIpRouteTable(currentRouter.routerAddr), false);

			for (int i = 0; i < ipRouteTable.size(); i++) {
				// get ipRouteType
				int ipRouteType = lib.parseIpRouteType(lib.getIpRouteType(
						ipRouteTable, i));

				if (ipRouteType == DIRECT) {
					// generate a sub net
					String ipRouteDest = lib.getIpRouteDest(ipRouteTable, i);
					String ipRouteMask = lib.getIpRouteMask(ipRouteTable, i);
					SubNet net = new SubNet(ipRouteDest, ipRouteMask);
					if (currentRouter.subNets.contains(net))
						currentRouter.subNets.add(net);
				}
				
				else if (ipRouteType == INDIRECT) {
					String ipRouteNextHop = lib.getIpRouteNextHop(ipRouteTable, i);
					Router router = new Router(ipRouteNextHop);
					if (!currentRouter.equals(router)) {
						RouteConnect rc = new RouteConnect(currentRouter.routerAddr, ipRouteNextHop);
						// establish a connection 
						if (!connect.contains(rc))
							connect.add(rc);
						// find new router in network
						if (!routerList.contains(router) && !processed.contains(router)) {
							routerList.add(router);
							router.routerName = lib.getName(router.routerAddr);
						}
					}
				}
				/* end of processing one row of ipRouteTable */
			}
			
			currentRouter.setVisited(true);
			processed.add(currentRouter);
		}
		
		// sub net discovery
		for (Iterator<Router> itr = processed.iterator(); itr.hasNext(); ) {
			Router currentRouter = itr.next();
			
			// get ipNetToMediaTable (ArpTable)
			ArrayList<ArrayList<Object>> ArpTable = lib.displayTable(lib
					.getIpNetToMediaTable(currentRouter.routerAddr), false);
			
			// find all hosts, and split them according to sub net
			for (int i = 0; i < ArpTable.size(); i++) {
				String mac = lib.getIpNetToMediaPhysAddress(ArpTable, i);
				String netAddr = lib.getIpNetToMediaNetAddress(ArpTable, i);
				Host h = new Host(netAddr, mac);
				currentRouter.insertHost(h);
			}
		}
		
	}

	/**
	 * print discovery
	 */
	public void print() {
		// TODO
	}
	
	/* ************************* members************************* */

	/**
	 * routers to be processed
	 */
	private ArrayList<Router> routerList = new ArrayList<Router>();
	/**
	 * routers processed
	 */
	private ArrayList<Router> processed = new ArrayList<Router>();
	/**
	 * store connection between routers
	 */
	private ArrayList<RouteConnect> connect = new ArrayList<RouteConnect> ();
	/**
	 * tools
	 */
	private Lib lib = new Lib();

	/*
	 * parsed type of ipRouteType
	 */
	private static final int OTHERS = 1;
	private static final int INVALID = 2;
	private static final int DIRECT = 3;
	private static final int INDIRECT = 4;
	private static final int ERROR = -1;
	/*
	 * parsed type of sysServices 
	 */
	private static final int TERMINAL = 0;
	private static final int SWITCH = 1;
}
